package com.pactera.madp.cp.service.sync.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.pactera.madp.cp.api.bo.SyncPsnInfoBo;
import com.pactera.madp.cp.api.entity.CorpEntity;
import com.pactera.madp.cp.api.entity.sync.SyncOrgInfoEntity;
import com.pactera.madp.cp.api.entity.sync.SyncQualifInfoEntity;
import com.pactera.madp.cp.api.entity.sync.SyncWxOrgRelation;
import com.pactera.madp.cp.common.config.FileUploadConfig;
import com.pactera.madp.cp.common.constant.Constants;
import com.pactera.madp.cp.common.enums.sync.HrServiceEnum;
import com.pactera.madp.cp.common.util.RedisUtil;
import com.pactera.madp.cp.common.util.WxApiUtils;
import com.pactera.madp.cp.config.SyncConfig;
import com.pactera.madp.cp.context.SyncStateContext;
import com.pactera.madp.cp.mapper.sync.SyncOrgInfoMapper;
import com.pactera.madp.cp.mapper.sync.SyncPsnInfoMapper;
import com.pactera.madp.cp.service.ICorpService;
import com.pactera.madp.cp.service.sync.HrPsnSyncBusinessService;
import com.pactera.madp.cp.service.sync.SyncQualifInfoService;
import com.pactera.madp.cp.service.sync.SyncWxOrgRelationService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.File;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@AllArgsConstructor
public class HrPsnSyncBusinessServiceImpl implements HrPsnSyncBusinessService {

    private final RedisTemplate redisTemplate;
    private final SyncWxOrgRelationService syncWxOrgRelationService;
    private final SyncQualifInfoService syncQualifInfoService;
    private final ICorpService corpService;
    private final SyncPsnInfoMapper syncPsnInfoMapper;
    private final SyncOrgInfoMapper syncOrgInfoMapper;
    private final FileUploadConfig config;
    private final SyncConfig syncConfig;

    @Override
    public Boolean syncBusiness() {
        String nowDate = DateUtil.format(new Date(), Constants.DATE_FORMAT);
        String serialNum = (String) redisTemplate.opsForValue().get(Constants.SYNC_HR_SERIAL_NUM);

        // 校验触发同步的阀值
        String thresholdKey = RedisUtil.buildKey(Constants.SYNC_PSN_THRESHOLD, serialNum);
        long threshold = redisTemplate.boundValueOps(thresholdKey).increment();
        if (!SyncStateContext.get().isExeBusiness() || threshold != HrServiceEnum.PSN.getSyncThreshold()) {
            log.info(SyncStateContext.get().getSyncSubType() + "-threshold-" + threshold + ",isExe-" + SyncStateContext.get().isExeBusiness());
            return false;
        } else {
            log.info("开始执行同步人员业务");
            // 重置触发值，避免二次执行时重复执行
            Set keys = redisTemplate.keys(Constants.SYNC_PSN_THRESHOLD + "*");
            keys.forEach(k -> redisTemplate.delete(k));
        }

        // 执行同步业务
        String lockKey = RedisUtil.buildKey(Constants.SYNC_PSN_BUSINESS_EMP2WX_LOCK, nowDate);

        try {
            // 获取同步业务的锁
            boolean isLocked = RedisUtil.getLock(lockKey, "1", Constants.EXPIRE_TIME, TimeUnit.SECONDS);
            if (!isLocked) {
                SyncStateContext.get().setSaveLog(false);
                return false;
            }
            log.info("获取人员业务同步锁成功");
            // 获取机构与企业微信部门关联列表
            List<SyncWxOrgRelation> orgRelationList = syncWxOrgRelationService.list();
            // 获取人员列表
            List<SyncPsnInfoBo> psnList = syncPsnInfoMapper.listPsn(Constants.SYNC_DEL_FLAG);
            // 过滤出指定的人员
            psnList = filterAppointPsn(psnList);
            // 获取资质列表
            List<SyncQualifInfoEntity> qualifList = syncQualifInfoService.list();
            // 设置人员资质
            cacheQualificationOfPsn(psnList, qualifList);
            // 缓存机构的关联列表
            cacheRootAndLeafOrgRelation(orgRelationList);
            // 构建批量执行的csv文件
            File csvFile = buildBatchCsv(orgRelationList, psnList);
            if (csvFile == null) {
                return false;
            }
            // 设置并缓存人员职位关系信息
            setAndCacheJobInfo(orgRelationList, psnList);
            // 获取企业
            CorpEntity corp = corpService.list().get(0);
            // 上传素材获取media_id
            String mediaId = WxApiUtils.uploadImageToTemps(corp.getCorpId(), csvFile, "file");
            // 执行批量同步成员任务
            executeBatchTask(corp, mediaId);

            return true;
        } finally {
            redisTemplate.delete(lockKey);
        }
    }

    // 过滤掉三级机构以下人员并更新表
    private void filterPsnAndUpdateDB() {
        // 获取全部机构
        List<SyncOrgInfoEntity> orgList = syncOrgInfoMapper.selectList(Wrappers.emptyWrapper());
        Map<String, String> orgMap = new HashMap<>();
        orgList.forEach(org -> orgMap.put(org.getId(), org.getTreeId()));
        Set<String> orgIds = orgMap.keySet();

        // 获取全部人员
        List<SyncPsnInfoBo> pnsList = syncPsnInfoMapper.listPsn(null);
        List<String> pnsNoList = new ArrayList<>();
        // 过滤掉二级机构以下人员
        pnsList.forEach(p -> {
            if (!orgIds.contains(p.getUnit())) {
                pnsNoList.add(p.getPsnNo());
            } /*else if (orgIds.contains(p.getUnit()) && orgMap.get(p.getUnit()).length() > 6) {
                pnsNoList.add(p.getPsnNo());
            }*/
        });

        // 更新表
        if (!pnsNoList.isEmpty()) {
            syncPsnInfoMapper.deleteBatchIds(pnsNoList);
        }
    }

    // 过滤叶子节点机构
    private List<SyncWxOrgRelation> filterLeafAndRootOrg(List<SyncOrgInfoEntity> orgList, List<SyncWxOrgRelation> orgRelationList) {
        List<SyncWxOrgRelation> newRelations = new ArrayList<>();
        orgRelationList.forEach(rel -> {
            for (SyncOrgInfoEntity org : orgList) {
                // 叶子节点机构的treeId为12位字符
                if (StrUtil.equals(rel.getHrOrgId(), org.getId()) && org.getTreeId().length() == 12) {
                    newRelations.add(rel);
                    break;
                }
                if (StrUtil.equals(rel.getHrOrgId(), org.getId()) && StrUtil.equals("-1", org.getOrgGroupCode())) {
                    newRelations.add(rel);
                    break;
                }
            }
        });
        return newRelations;
    }

    // 过滤出指定人员
    private List<SyncPsnInfoBo> filterAppointPsn(List<SyncPsnInfoBo> psnList) {
        List<SyncPsnInfoBo> newPsnList = new ArrayList<>();
        if (syncConfig.getPsnCtrlFlag()) {
            Set<String> jobNoList = syncConfig.getPsnJobNo();
            log.info("过滤人员：{}", jobNoList);
            for (SyncPsnInfoBo p : psnList) {
                if (jobNoList.contains(p.getJobNo())) {
                    newPsnList.add(p);
                    log.info("已过滤出人员：{}", p.getJobNo());
                }
            }
            return newPsnList;
        }
        return psnList;
    }

    // 缓存人员资质
    private void cacheQualificationOfPsn(List<SyncPsnInfoBo> psnList, List<SyncQualifInfoEntity> qualifList) {
        if (psnList.isEmpty() || qualifList.isEmpty()) {
            return;
        }
        Map<String, String> psnNoQualifMap = new HashMap<>();
        qualifList.forEach(q -> {
            String qualifications = psnNoQualifMap.get(q.getPsnNo());
            if (StrUtil.isEmpty(qualifications)) {
                psnNoQualifMap.put(q.getPsnNo(), q.getQualification() + ";");
            } else {
                psnNoQualifMap.put(q.getPsnNo(), qualifications + q.getQualification() + ";");
            }
        });

        Map<String, String> jobNoQualifMap = new HashMap<>();
        psnList.forEach(p -> {
            String qualifications = psnNoQualifMap.get(p.getPsnNo());
            if (StrUtil.isEmpty(qualifications)) {
                qualifications = null;
            } else {
                List<String> array = CollUtil.toList(qualifications.split(";"));
                Map<String,Object> extattr = new HashMap();
                List<Map<String,Object>> attrs = new ArrayList<>();
                array.forEach(q -> {
                    Map<String,String> text = new HashMap<>();
                    text.put("value", q);
                    Map<String,Object> data = new HashMap<>();
                    data.put("type", 0);
                    data.put("name", "资质");
                    data.put("text", text);
                    attrs.add(data);
                });
                extattr.put("qualification", attrs);
                qualifications = JSONUtil.toJsonStr(extattr);
            }
            jobNoQualifMap.put(p.getJobNo(), qualifications);
        });
        // 缓存资质信息
        redisTemplate.opsForValue().set(Constants.SYNC_QUALIF_INFO, JSONUtil.toJsonStr(jobNoQualifMap));
    }

    // 缓存叶子节点机构和根机构的关联列表
    public void cacheRootAndLeafOrgRelation(List<SyncWxOrgRelation> relationList) {
        if (relationList.isEmpty()) {
            return;
        }
        redisTemplate.delete(Constants.SYNC_ORG_LEAF_ROOT);
        redisTemplate.opsForList().leftPushAll(Constants.SYNC_ORG_LEAF_ROOT, relationList);
    }

    // 按部门过滤人员并缓存列表
    private void setPsnListByOrg(List<SyncWxOrgRelation> orgRelationList, List<SyncPsnInfoBo> psnList) {
        // 清空之前的相关人员机构缓存列表
        Set keys = redisTemplate.keys(Constants.SYNC_PSN_BY_ORG + "*");
        keys.forEach(k -> {
            redisTemplate.delete(k);
        });
        // 按机构过滤人员
        List<SyncPsnInfoBo> list = new ArrayList<>();
        orgRelationList.forEach(rel -> {
            psnList.forEach(p -> {
                if (StrUtil.equals(rel.getHrOrgId(), p.getUnit())) {
                    list.add(p);
                }
            });
            // 按机构缓存人员列表
            if (!list.isEmpty()) {
                String key = Constants.SYNC_PSN_BY_ORG + rel.getWxDeptId();
                redisTemplate.opsForList().leftPushAll(key, list);
                list.clear();
            }
        });
    }

    // 构建批量执行的csv文件
    private File buildBatchCsv(List<SyncWxOrgRelation> orgRelationList, List<SyncPsnInfoBo> psnList) {
        if (orgRelationList.isEmpty() || psnList.isEmpty()) {
            log.error("同步人员数据列表为空");
            return null;
        }
        Map<String, Integer> orgWxMap = new HashMap<>();
        orgRelationList.forEach(rel -> {
            orgWxMap.put(rel.getHrOrgId(), rel.getWxDeptId());
        });
        List<String> batchData = new ArrayList<>();
        String template = "{},{},{},,,{},,{},,,,,,{},";
        // 构建主题行
        batchData.add(Constants.SYNC_PSN_CSV_TEMPLATE);
        for (SyncWxOrgRelation rel : orgRelationList) {
            for (SyncPsnInfoBo bo : psnList) {
                if (StrUtil.equals(rel.getHrOrgId(), bo.getUnit())) {
                    String gender = Constants.SYNC_SEX_FLAG.equals(bo.getSex()) ? "1" : "2";
                    String mobile = bo.getMobile();
                    if (!StrUtil.isEmpty(mobile)) {
                        mobile = mobile.length() > 11 ? mobile.substring(0, 11) : mobile;
                    }
                    String data = StrUtil.format(template, bo.getUserName(), bo.getJobNo(), mobile,
                            orgWxMap.get(bo.getUnit()), gender, "0");
                    batchData.add(data);
                }
            }
        }
        // 生成csv文件
        String filePath = StrUtil.format("{}{}{}{}",config.getRealPath(), File.separator,
                DateUtil.format(new Date(), Constants.DATE_FORMAT), "_batch_user.csv");
        File csvFile = FileUtil.writeLines(batchData, filePath, CharsetUtil.UTF_8);
        log.info("生成人员csv文件成功");
        return csvFile;
    }

    // 设置并缓存人员职位关系信息
    private void setAndCacheJobInfo(List<SyncWxOrgRelation> orgRelationList, List<SyncPsnInfoBo> psnList) {
        Map<String, String> psnJobInfo = new HashMap<>();
        for (SyncWxOrgRelation rel : orgRelationList) {
            for (SyncPsnInfoBo bo : psnList) {
                if (StrUtil.equals(rel.getHrOrgId(), bo.getUnit())) {
                    // 因为职位属于敏感信息，不能上送到企业微信端，所以暂缓存本地
                    String jobName = StrUtil.isEmpty(bo.getJobName()) ? "" : bo.getJobName();
                    psnJobInfo.put(bo.getJobNo(), bo.getJobName());
                }
            }
        }
        redisTemplate.opsForValue().set(Constants.SYNC_PSN_JOB_INFO, JSONUtil.toJsonStr(psnJobInfo));
    }


    // 批量异步同步企业微信成员
    private String executeBatchTask(CorpEntity corp, String mediaId) {
        Map<String,String> callback = new HashMap<>();
        callback.put("url", corp.getEventCallback());
        callback.put("token", corp.getToken());
        callback.put("encodingaeskey", corp.getEncodingAesKey());
        Map<String,Object> body = new HashMap<>();
        body.put("media_id", mediaId);
        body.put("callback", callback);

        String jobId = WxApiUtils.asyncBatchUser(corp.getCorpId(), JSONUtil.toJsonStr(body));
        if (StrUtil.isEmpty(jobId)) {
            throw new RuntimeException("异步全量同步成员任务执行失败");
        }
        log.info("批量同步到企业微信成员执行完毕");
        return jobId;
    }

}
